
/* <<< COPYRIGHT START >>>
 * Copyright 2006-Present OxygenSoftwareLibrary.com
 * Licensed under the GNU Lesser General Public License.
 * http://www.gnu.org/licenses/lgpl.html
 * 
 * @author: Ugorji Dick-Nwoke
 * <<< COPYRIGHT END >>>
 */


package oxygen.util;

import java.io.Reader;
import java.io.Writer;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import oxygen.web.OxygenErrorModel;
import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.cache.URLTemplateLoader;
import freemarker.core.Environment;
import freemarker.ext.beans.BeansWrapper;
import freemarker.template.*;

public class FreemarkerTemplateHelper implements Closeable { 

  private Configuration cfg;
  private Map defaultStaticModels;
    
  protected FreemarkerTemplateHelper() {
  }
  
  public FreemarkerTemplateHelper(String[] templates0, Map defaultStaticModels0) {
    init(templates0, defaultStaticModels0);
  }

  protected void init(String[] templates, Map defaultStaticModels0) {
    defaultStaticModels = defaultStaticModels0;
    cfg = new Configuration();
    
    TemplateLoader[] templateLoaders = new TemplateLoader[templates.length];
    for(int i = 0; i < templates.length; i++) {
      templateLoaders[i] = new OxyTemplateLoader(templates[i]);
    }
    
    cfg.setTemplateLoader(new MultiTemplateLoader(templateLoaders));
    cfg.setObjectWrapper(new DefaultObjectWrapper());
    cfg.setTemplateExceptionHandler(this.new OxyTemplateExceptionHandler());
  }
  
  public void write(String templatefile, Map model, Writer writer) throws Exception {
    write(templatefile, model, null, writer);
  }
  
  public void write(String templatefile, Map model, Map staticModelStrings, Writer writer) throws Exception {
    Map model2 = new HashMap(model);
    Map[] sm2 = new Map[]{defaultStaticModels, staticModelStrings};
    for(int i = 0; i < sm2.length; i++) {
      if(sm2[i] == null || sm2[i].size() == 0) continue;
      TemplateHashModel thm = BeansWrapper.getDefaultInstance().getStaticModels();
      for(Iterator itr = sm2[i].entrySet().iterator(); itr.hasNext(); ) {
        Map.Entry entry = (Map.Entry)itr.next();
        String key = (String)entry.getKey();
        String val = (String)entry.getValue();
        model2.put(key, thm.get(val));
      }
    }
    rawWrite(templatefile, model2, writer);
  }
  
  public void rawWrite(String templatefile, Map model, Writer writer) throws Exception {
    Template t = cfg.getTemplate(templatefile);
    t.process(model, writer);
  }
  
  public void rawWrite(Reader r, Map model, Writer writer) throws Exception {
    Template t = new Template("blah-XYZUgorji-" + OxygenUtils.getUniqueIntID(1000000), r, cfg);
    t.process(model, writer);
  }
  
  public void close() { 
  }
  
  public void handleError(Exception thr, Writer w) throws Exception {
    try {
      OxygenErrorModel.includeErrorView(thr, w, this);
    } catch(Exception exc) {
      throw exc;
    } catch(Throwable thr2) {
      throw new RuntimeException(thr2);
    }
  }
  
  private class OxyTemplateExceptionHandler implements TemplateExceptionHandler {
    public void handleTemplateException(TemplateException te, Environment env, Writer writer) throws TemplateException {
      try {
        Exception thr = te.getCauseException();
        thr = ((thr == null) ? te : thr);
        handleError(thr, writer);
      } catch(TemplateException te2) {
        throw te2;
      } catch(Exception e2) {
        throw new TemplateException(e2, env);
      }
    }
  }
  
  private static class OxyTemplateLoader extends URLTemplateLoader {
    private String basepath;
    
    private OxyTemplateLoader(String basepath0) {
      basepath = basepath0.replace('\\', '/');
      basepath = StringUtils.trim(basepath, '/');
    }
    
    protected URL getURL(String name) {
      return Thread.currentThread().getContextClassLoader().getResource(basepath + '/' + name);
    }

  }
  
}

